﻿// Inner Fire 游戏引擎库
// DirectX主类分装 - 管线
//
// Copyright (c) 2023 by 尔西大帝. All rights reserved.
//
// 用于管线相关的项目
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2024-11-24

#include <dx_graphics.h>
#include <dx_scene/dx_scene.h>

namespace ifire {

void DxGraphics::InitPipeline() {
  // 重置命令列表，为执行初始化命令做好准备工作
  HASSERT(command_list_->Reset(command_allocator_.Get(), nullptr));

  // 设置默认相机位置
  camera_.SetPosition(0.0f, 2.0f, -15.0f);

  scene_->InitPipeline();

  // 执行初始化命令
  HASSERT(command_list_->Close());
  ID3D12CommandList* cmd_lists[] = {command_list_.Get()};
  command_queue_->ExecuteCommandLists(_countof(cmd_lists), cmd_lists);

  // 等待初始化完成
  FlushCommandQueue();

  dxutils::log("Init pipeline complete.");

  // 进行一次计算（这就相当于画一次而已）
  scene_->DoComputeWork();
}

void DxGraphics::BuildRootSignature() {
  // 用于纹理的描述符表
  CD3DX12_DESCRIPTOR_RANGE texTable;
  texTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);

  // 根参数可以是描述符表，根描述符，或根常量
  CD3DX12_ROOT_PARAMETER slot_root_paramater[4];
  // 设置描述符区域的数量，指向描述符区域数组的指针
  slot_root_paramater[0].InitAsDescriptorTable(
      1, &texTable, D3D12_SHADER_VISIBILITY_PIXEL); // 注意这个是描述符表
  slot_root_paramater[1].InitAsConstantBufferView(0);
  slot_root_paramater[2].InitAsConstantBufferView(1);
  slot_root_paramater[3].InitAsConstantBufferView(2);

  // 这个东西是静态的，用于采样器
  auto staticSamplers = GetStaticSamplers();

  // 根签名由一组根参数构成
  // 注意这里和之前的变化，增加了采样器的数量和地址。
  CD3DX12_ROOT_SIGNATURE_DESC root_signature_desc(4, slot_root_paramater,
      (UINT)staticSamplers.size(), staticSamplers.data(),
      D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);

  // 序列化根签名
  ComPtr<ID3DBlob> serialized_root_sign = nullptr;
  ComPtr<ID3DBlob> error_blob = nullptr;
  HRESULT hr = D3D12SerializeRootSignature(&root_signature_desc,
      D3D_ROOT_SIGNATURE_VERSION_1, serialized_root_sign.GetAddressOf(),
      error_blob.GetAddressOf());
  // 常规错误检查
  if (error_blob != nullptr) {
    dxutils::log((char*)error_blob->GetBufferPointer());
  }
  HASSERT(hr);

  // 创建根签名
  HASSERT(device_->CreateRootSignature(0, //
      serialized_root_sign->GetBufferPointer(),
      serialized_root_sign->GetBufferSize(),
      IID_PPV_ARGS(root_signature_.GetAddressOf())));
}

void DxGraphics::BuildShaderAndInputLayout() {

  // 设置预制值
  const D3D_SHADER_MACRO defines[] = {
      "FOG", "1", // 雾效
      NULL, NULL  // 这为什么要两个NULL？用来对齐？
  };

  // 用于Alpha测试
  const D3D_SHADER_MACRO alpha_test_defines[] = {//
      "FOG", "1",                                // 雾效
      "ALPHA_TEST", "1",                         // 用于Alpha测试
      NULL, NULL};

  shaders_["StandardVS"] =
      dxutils::compile_shader("shaders/Default.hlsl", nullptr, "VS", "vs_5_0");

  shaders_["OpaquePS"] =
      dxutils::compile_shader("shaders/Default.hlsl", defines, "PS", "ps_5_0");

  shaders_["AlphaTestPS"] = dxutils::compile_shader(
      "shaders/Default.hlsl", alpha_test_defines, "PS", "ps_5_0");

  input_layout_ = {
      {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,
          D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
      {"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12,
          D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
      {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24,
          D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
  };

  //
  // 用于树公告牌
  //
  shaders_["TreeSpriteVS"] = dxutils::compile_shader(
      "shaders/TreeSprite.hlsl", nullptr, "VS", "vs_5_0");
  shaders_["TreeSpriteGS"] = dxutils::compile_shader(
      "shaders/TreeSprite.hlsl", nullptr, "GS", "gs_5_0");
  shaders_["TreeSpritePS"] = dxutils::compile_shader(
      "shaders/TreeSprite.hlsl", alpha_test_defines, "PS", "ps_5_0");

  tree_sprite_input_layout_ = {
      {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,
          D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
      {"SIZE", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12,
          D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
  };

  //
  // 用于模糊
  //
  shaders_["HorzBlurCS"] = dxutils::compile_shader(
      "Shaders\\Blur.hlsl", nullptr, "HorzBlurCS", "cs_5_0");
  shaders_["VertBlurCS"] = dxutils::compile_shader(
      "Shaders\\Blur.hlsl", nullptr, "VertBlurCS", "cs_5_0");

  // 用于GPU波浪
  const D3D_SHADER_MACRO waveDefines[] = {"DISPLACEMENT_MAP", "1", NULL, NULL};
  shaders_["WavesVS"] = dxutils::compile_shader(
      "Shaders\\Default.hlsl", waveDefines, "VS", "vs_5_0");
  shaders_["WavesUpdateCS"] = dxutils::compile_shader(
      "Shaders\\WaveSim.hlsl", nullptr, "UpdateWavesCS", "cs_5_0");
  shaders_["WavesDisturbCS"] = dxutils::compile_shader(
      "Shaders\\WaveSim.hlsl", nullptr, "DisturbWavesCS", "cs_5_0");

  // 用于索贝尔算子
  shaders_["CompositeVS"] = dxutils::compile_shader(
      "Shaders\\Composite.hlsl", nullptr, "VS", "vs_5_0");
  shaders_["CompositePS"] = dxutils::compile_shader(
      "Shaders\\Composite.hlsl", nullptr, "PS", "ps_5_0");
  shaders_["SobelCS"] = dxutils::compile_shader(
      "Shaders\\Sobel.hlsl", nullptr, "SobelCS", "cs_5_0");

  shaders_["TessVS"] = dxutils::compile_shader(
      "Shaders\\Tessellation.hlsl", nullptr, "VS", "vs_5_0");
  shaders_["TessHS"] = dxutils::compile_shader(
      "Shaders\\Tessellation.hlsl", nullptr, "HS", "hs_5_0");
  shaders_["TessDS"] = dxutils::compile_shader(
      "Shaders\\Tessellation.hlsl", nullptr, "DS", "ds_5_0");
  shaders_["TessPS"] = dxutils::compile_shader(
      "Shaders\\Tessellation.hlsl", nullptr, "PS", "ps_5_0");

  tess_input_layout_ = {{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,
      D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}};
}

} // namespace ifire